#include "proto.h"
#include <signal.h>
#include <string.h>
#include <errno.h>

#define MAX_CONNECT 1024
#define BUFFSIZE    128

static int max_two_number (int a, int b);
int main (void)
{
	int tcp_socket;
	struct sockaddr_in myaddr;
	fd_set rset, tmp_set;
	int max_fd, i = 0;
	int connected_arr[MAX_CONNECT] = {0};
	int cnt = 0;
	char buf[BUFFSIZE] = {0};
	struct sigaction act;
	int ret = 0;

	/*SIGCHLD*/
	act.sa_handler = SIG_DFL;
	act.sa_flags = SA_NOCLDWAIT;
	sigaction (SIGCHLD, &act, NULL);

	tcp_socket = socket (AF_INET, SOCK_STREAM, 0);
	if (-1 == tcp_socket) {
		perror ("socket()");
		exit (1);
	}
	//解决地址复用 
	int val = 1;
	if (-1 == setsockopt (tcp_socket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)))
	{
		perror ("setsockopt()");
		goto ERROR;
	}
	
	myaddr.sin_family = AF_INET;
	myaddr.sin_port = htons (atoi(SERVER_PROT));
	myaddr.sin_addr.s_addr = INADDR_ANY;
	if (-1 == bind (tcp_socket, (struct sockaddr *)&myaddr, sizeof(myaddr))) {
		perror ("bind()");
		goto ERROR;
	}
	
	//设置监听
	if(-1 == listen (tcp_socket, 32)) {
		perror ("listen()");
		goto ERROR;
	}
	/*
	   需要监听客户端是否有请求到来
	   需要监听标准输入是否有数据, 如果有数据将发送给所有已连接的客户端 
	   需要监听所有已连接成功的客户端是否有数据到来
	 */
	//清空读集 
	FD_ZERO (&rset);
	FD_SET (tcp_socket, &rset);
	FD_SET (0, &rset);
	max_fd = max_two_number (tcp_socket, 0);
	
	while (1) {
		tmp_set = rset;
		ret = select (max_fd + 1, &tmp_set, NULL, NULL, NULL);
		if (-1 == ret) {
			if (EINTR == ret) {
				//假错
				continue;
			}
			perror ("select ()");
			goto ERROR;
		}

		//监听的事件发生了 
		if (FD_ISSET (tcp_socket, &tmp_set) && ret > 0) {
			//证明现在有客户端的连接请求到来了 
			connected_arr[i] = accept (tcp_socket, NULL, NULL);
			if (-1 == connected_arr[i]) {
				perror ("accept()");
				goto ERROR;
			}
			FD_SET (connected_arr[i], &rset);
			//最大的文件描述符可能会发生变化
			max_fd = max_two_number (max_fd, connected_arr[i]);
			i++;
		} else if ((FD_ISSET (0, &tmp_set)) && ret> 0) {
			//证明标准输入缓冲区中有数据到来了
			cnt = read (0, buf, BUFFSIZE);
			for (int j = 0; j < i; j++) {
				write (connected_arr[j], buf, cnt);
			}
		} else {
			//客户有数据到来 
			for (int j = 0; j < i; j++) {
				if (FD_ISSET(connected_arr[j], &tmp_set)) {
					bzero (buf, BUFFSIZE);
					cnt = read (connected_arr[j], buf, BUFFSIZE);
					if (-1 == cnt) {
						perror ("read()");
						goto ERROR;
					}
					if (0 == cnt) {
						//客户端已经断开连接了
						FD_CLR (connected_arr[j], &rset);
						close (connected_arr[j]);
						//将数组中某一个元素移除, 比如 0 1 2 3 4 中的3移除, 需要将4往前移1下
						memcpy (connected_arr + j, connected_arr + j + 1, (i - (j +1)) * sizeof(int));
						i--;
						j--;
					}
					puts (buf);
				}
			}
		} 
	}
	close (tcp_socket);
	return 0;
ERROR:
	close (tcp_socket);
}

static int max_two_number (int a, int b)
{
	return a > b ? a : b;
}


